#include "Requestor.hpp"
#include "../comm/UUIDUtil.hpp"

namespace ns_rpc_call
{
    class RpcCaller
    {
    public:
        using ptr = std::shared_ptr<RpcCaller>;
        using JsonAsyncResponse = std::future<Json::Value>;
        using JsonResponseCallback = std::function<void(const Json::Value &)>;
        RpcCaller(const ns_Req::Requestor::ptr &req)
            : _req(req)
        {
        }

        bool Call(const BaseConnection::ptr &conn, const std::string &method_name, Json::Value paras, Json::Value result)
        {
            // 1.构建消息
            auto rpc_req = MessageFactory::Createmsg<RpcRequest>();
            rpc_req->Setid(ns_uuid::UUIDUtil::uuid());
            rpc_req->SetMethod(method_name);
            rpc_req->SetMtype(ns_fields::Mtype::RPC_REQ);
            rpc_req->SetParameters(paras);
            // 2.发送消息
            BaseMessage::ptr rpc_msg;
            bool ret = _req->Send(conn, std::dynamic_pointer_cast<RpcRequest>(rpc_req), rpc_msg);
            if (ret == false)
            {
                LOG(ERROR, "发送RpcRequest失败!!!");
                return false;
            }
            // 3.接收响应
            auto rpc_rsp = std::dynamic_pointer_cast<RpcResponse>(rpc_msg);
            if (rpc_rsp.get() == nullptr)
            {
                LOG(ERROR, "Rpc响应向下转换失败!!!");
                return false;
            }
            else if (rpc_rsp->GetRcode() != ns_fields::Rcode::RCODE_OK)
            {
                LOG(ERROR, "响应内容不正确!!!");
                return false;
            }
            result = rpc_rsp->GetResult();
            return true;
        }
        bool Call(const BaseConnection::ptr &conn, const std::string &method_name, Json::Value paras, JsonAsyncResponse result)
        {
            // 1.构建消息
            auto rpc_req = MessageFactory::Createmsg<RpcRequest>();
            rpc_req->Setid(ns_uuid::UUIDUtil::uuid());
            rpc_req->SetMethod(method_name);
            rpc_req->SetMtype(ns_fields::Mtype::RPC_REQ);
            rpc_req->SetParameters(paras);
            // 2.给服务端发送异步请求，用回调函数来接受异步结果
            auto json_promise = std::shared_ptr<std::promise<Json::Value>>();
            result = json_promise->get_future();
            // 因为我的result是BaseMessage类型的，但用户需要的是Message里面的body
            ns_Req::Requestor::Requestcb cb = std::bind(&RpcCaller::Callback, this, json_promise, std::placeholders::_1);
            bool ret = _req->Send(conn, std::dynamic_pointer_cast<BaseMessage>(rpc_req), cb);
            if (ret == false)
            {
                LOG(ERROR, "Rpc请求失败");
                return false;
            }
            return true;
        }
        bool Call(const BaseConnection::ptr &conn, const std::string &method_name, Json::Value paras, JsonResponseCallback cb)
        {
            // 1.构建消息
            auto rpc_req = MessageFactory::Createmsg<RpcRequest>();
            rpc_req->Setid(ns_uuid::UUIDUtil::uuid());
            rpc_req->SetMethod(method_name);
            rpc_req->SetMtype(ns_fields::Mtype::RPC_REQ);
            rpc_req->SetParameters(paras);
            
            ns_Req::Requestor::Requestcb rcb = std::bind(&RpcCaller::Callback1, this, cb, std::placeholders::_1);
            bool ret = _req->Send(conn,std::dynamic_pointer_cast<BaseMessage>(rpc_req), rcb);
            if(ret == false)
            {
                LOG(ERROR,"回调Rpc请求失败");
                return false;
            }
            return true;
        }

    private:
        void Callback1(const JsonResponseCallback& cb, const BaseMessage::ptr &msg)
        {
            auto rpc_rsp = std::dynamic_pointer_cast<RpcResponse>(msg);
            if (rpc_rsp.get() == nullptr)
            {
                LOG(ERROR, "Rpc响应向下转换失败!!!");
                return;
            }
            else if (rpc_rsp->GetRcode() != ns_fields::Rcode::RCODE_OK)
            {
                LOG(ERROR, "响应内容不正确!!!");
                return;
            }
            cb(rpc_rsp->GetResult());
        }
        void Callback(std::shared_ptr<std::promise<Json::Value>> promise, const BaseMessage::ptr &msg)
        {
            auto rpc_rsp = std::dynamic_pointer_cast<RpcResponse>(msg);
            if (rpc_rsp.get() == nullptr)
            {
                LOG(ERROR, "Rpc响应向下转换失败!!!");
                return;
            }
            else if (rpc_rsp->GetRcode() != ns_fields::Rcode::RCODE_OK)
            {
                LOG(ERROR, "响应内容不正确!!!");
                return;
            }
            promise->set_value(rpc_rsp->GetResult());
        }
        ns_Req::Requestor::ptr _req;
    };
}